#include <iostream>
#include <vector>
#include <mutex>
#include "LockGuard.hpp"
#include "Thread.hpp"

using namespace ThreadModule;

class ThreadData
{
public:
    ThreadData(int &tickets, const std::string &name, pthread_mutex_t &mutex)
        : _tickets(tickets), _name(name), _total(0), _mutex(mutex)
    {
    }
    ~ThreadData()
    {
    }
public:
    int &_tickets; // 所有的线程，最后都会引用同一个全局的g_tickets
    std::string _name;
    int _total;
    pthread_mutex_t &_mutex;
};


/* // pthread_mutex_t + LockGuard
int g_tickets = 2000;
const int num = 4;

void route(ThreadData *td)
{
    while (true)
    {
        LockGuard guard(&td->_mutex); 

        if (td->_tickets > 0) 
        {
            usleep(1000);
            printf("%s running, get tickets: %d\n", td->_name.c_str(), td->_tickets); 
            td->_tickets--;                                                    
            td->_total++;
        }
        else
        {
            break;
        }
    }
}
int main()
{
    pthread_mutex_t mutex;
    pthread_mutex_init(&mutex, nullptr);

    std::vector<Thread<ThreadData *>> threads;
    std::vector<ThreadData *> datas;
    // 1. 创建一批线程
    for (int i = 0; i < num; i++)
    {
        std::string name = "thread-" + std::to_string(i + 1);
        ThreadData *td = new ThreadData(g_tickets, name, mutex);
        threads.emplace_back(route, td, name);
        datas.emplace_back(td);
    }

    // 2. 启动 一批线程
    for (auto &thread : threads)
    {
        thread.Start();
    }

    // 3. 等待一批线程
    for (auto &thread : threads)
    {
        thread.Join();
        // std::cout << "wait thread done, thread is: " << thread.name() << std::endl;
    }

    sleep(1);
    // 4. 输出统计数据
    for (auto data : datas)
    {
        std::cout << data->_name << " : " << data->_total << std::endl;
        delete data;
    }

    return 0;
}
*/



 // 全局 pthread_mutex_t mutex
pthread_mutex_t gmutex = PTHREAD_MUTEX_INITIALIZER;
int g_tickets = 2000; 
const int num = 4;

void route(ThreadData *td)
{
    while (true)
    {
        // 访问临界资源的代码，叫做临界区！--- 我们加锁，本质就是把并行执行 --- 串行执行 --- 加锁的粒度要约细越好
        // 加锁 : 竞争锁是自由竞争的，竞争锁的能力太强的线程，会导致其他线程抢不到锁 --- 造成了其他线程的饥饿问题
        pthread_mutex_lock(&gmutex); 
        if (td->_tickets > 0)        
        {
            // 模拟一次抢票的逻辑
            usleep(1000);
            printf("%s running, get tickets: %d\n", td->_name.c_str(), td->_tickets); 
            td->_tickets--;                                                           
            pthread_mutex_unlock(&td->_mutex); // 解锁
            td->_total++;
        }
        else
        {
            pthread_mutex_unlock(&td->_mutex); // 解锁
            break;
        }
    }
}
int main()
{
    std::vector<Thread<ThreadData *>> threads;
    std::vector<ThreadData *> datas;
    // 1. 创建一批线程
    for (int i = 0; i < num; i++)
    {
        std::string name = "thread-" + std::to_string(i + 1);
        ThreadData *td = new ThreadData(g_tickets, name, gmutex);
        threads.emplace_back(route, td, name);
        datas.emplace_back(td);
    }

    // 2. 启动 一批线程
    for (auto &thread : threads)
    {
        thread.Start();
    }

    // 3. 等待一批线程
    for (auto &thread : threads)
    {
        thread.Join();
    }

    sleep(1);
    // 4. 输出统计数据
    for (auto data : datas)
    {
        std::cout << data->_name << " : " << data->_total << std::endl;
        delete data;
    }

    pthread_mutex_destroy(&gmutex);

    return 0;
}




/*  // C++11 std::mutex
class ThreadData
{
public:
    ThreadData(int &tickets, const std::string &name, std::mutex &mutex)
        : _tickets(tickets), _name(name), _total(0), _mutex(mutex)
    {
    }
    ~ThreadData()
    {
    }

public:
    int &_tickets; // 所有的线程，最后都会引用同一个全局的g_tickets
    std::string _name;
    int _total;
    std::mutex &_mutex;
};

int g_tickets = 2000;
const int num = 4;

void route(ThreadData *td)
{
    while (true)
    {
        td->_mutex.lock();
        //std::lock_guard<std::mutex> lock(td->_mutex);
        if (td->_tickets > 0) 
        {
            usleep(1000);
            printf("%s running, get tickets: %d\n", td->_name.c_str(), td->_tickets); 
            td->_tickets--;                                                           
            td->_total++;
            td->_mutex.unlock();
        }
        else
        {
            td->_mutex.unlock();
            break;
        }
    }
}
int main()
{
    std::mutex mutex;
    std::vector<Thread<ThreadData *>> threads;
    std::vector<ThreadData *> datas;
    // 1. 创建一批线程
    for (int i = 0; i < num; i++)
    {
        std::string name = "thread-" + std::to_string(i + 1);
        ThreadData *td = new ThreadData(g_tickets, name, mutex);
        threads.emplace_back(route, td, name);
        datas.emplace_back(td);
    }

    // 2. 启动 一批线程
    for (auto &thread : threads)
    {
        thread.Start();
    }

    // 3. 等待一批线程
    for (auto &thread : threads)
    {
        thread.Join();
    }

    sleep(1);
    // 4. 输出统计数据
    for (auto data : datas)
    {
        std::cout << data->_name << " : " << data->_total << std::endl;
        delete data;
    }

    return 0;
}
*/
